/**
 * 物理库相关操作
 * by wyy
 */
class physicsUtil extends eui.Component implements eui.UIComponent {
    private static instance: physicsUtil;
    public phyWorld: p2.World;
    public phyFactor: number = 50;
    public debugDraw: p2DebugDraw;
    public debugSprite: egret.Sprite;

    public bulletMat: p2.Material;
    public wallMat: p2.Material;
    public brickMat: p2.Material;

    constructor() {
        super();
        this.init();
    }
    static getInstance(): physicsUtil {
        (!this.instance) && (this.instance = new physicsUtil());
        return this.instance;
    }
    private init() {
    }
    //创建碰撞规则
    private createMaterial() {
        this.bulletMat = new p2.Material(1);
        this.wallMat = new p2.Material(2);
        this.brickMat = new p2.Material(3);
        //球与墙的碰撞规则
        let opt1 = {
            surfaceVelocity: 0,
            restitution: 1,
            friction: 0,
            stiffness: 1e7,
            relaxation: 0.01,
            frictionRelaxation: 0,
            frictionStiffness: 0
        }
        var material1 = new p2.ContactMaterial(this.bulletMat, this.wallMat, opt1);
        this.phyWorld.addContactMaterial(material1);
        //球与球穿透
        let opt2 = {
            surfaceVelocity: 0,
            restitution: 0,
            friction: 0,
            stiffness: 1e-10,
            relaxation: 1,
            frictionRelaxation: 0,
            frictionStiffness: 1
        }
        var material2 = new p2.ContactMaterial(this.bulletMat, this.bulletMat, opt2);
        this.phyWorld.addContactMaterial(material2);
        //球与方块
        let opt3 = {
            surfaceVelocity: 0,
            restitution: 1,
            friction: 0,
            stiffness: 1e7,
            relaxation: 0.01,
            frictionRelaxation: 0,
            frictionStiffness: 0
        }
        var material3 = new p2.ContactMaterial(this.brickMat, this.bulletMat, opt3);
        this.phyWorld.addContactMaterial(material3);

    }
    //创建墙
    public createWall({ width = 100, height = 10, color = 0xffffff, mass = 0, position = [0, 0] }): p2.Body {
        let [x, y] = this.posEgretToP2(position[0], position[1]);
        let shape = new egret.Shape();
        shape.graphics.beginFill(color);
        shape.graphics.drawRect(0, 0, width, height);
        shape.graphics.endFill();
        let phyShape = new p2.Box({ width: width / this.phyFactor, height: height / this.phyFactor });
        phyShape.material = this.wallMat;
        let phyBody: p2.Body =
            new p2.Body({
                mass: mass,
                position: [x, y]
            });
        phyBody.addShape(phyShape);
        this.phyWorld.addBody(phyBody);
        phyBody.displays = [shape];

        shape.width = (<p2.Box>phyShape).width * this.phyFactor;
        shape.height = (<p2.Box>phyShape).height * this.phyFactor;
        shape.anchorOffsetX = shape.width / 2;
        shape.anchorOffsetY = shape.height / 2;

        return phyBody;
    }
    //创建物理世界
    public createPhyWorld() {
        this.phyWorld = new p2.World();
        let world = this.phyWorld;
        world.sleepMode = p2.World.BODY_SLEEPING;

        //取消重力
        world.applyGravity = false;
        world.applyDamping = false;

        //创建材质碰撞规则
        this.createMaterial();

        /*this.debugDraw = new p2DebugDraw(this.phyWorld)
        this.debugSprite = new egret.Sprite();
        this.debugDraw.setSprite(this.debugSprite);*/

        //物体坐标同步
        this.addEventListener(egret.Event.ENTER_FRAME, () => {
            world.step(1 / 60);
            let l = world.bodies.length;
            for (let i: number = 0; i < l; i++) {
                this.syncDisplay(world.bodies[i]);
            }
        }, this);


    }

    //将显示与物理同步
    private syncDisplay(body: p2.Body) {
        let shape = body.displays[0];
        let stageHeight = egret.MainContext.instance.stage.stageHeight;
        let p = shape.parent.globalToLocal(body.position[0] * this.phyFactor, stageHeight - (body.position[1] * this.phyFactor));
        if (shape) {
            shape.x = p.x;
            shape.y = p.y;
            shape.rotation = 360 - (body.angle + body.shapes[0].angle) * 180 / Math.PI;
        }
    }
    //p2和egret坐标变换
    public posP2ToEgret(x: number, y: number): number[] {
        let stageH = egret.MainContext.instance.stage.stageHeight;
        let rX = x * this.phyFactor;
        let rY = (stageH - y) * this.phyFactor;
        return [rX, rY];
    }
    public posEgretToP2(x: number, y: number): number[] {
        let stageH = egret.MainContext.instance.stage.stageHeight;
        let rX = x / this.phyFactor;
        let rY = (stageH - y) / this.phyFactor;
        return [rX, rY];
    }
}